package cn.jiaqiang.chatgpt.data.trigger.http;


import cn.jiaqiang.chatgpt.data.domain.auth.service.IAuthService;
import cn.jiaqiang.chatgpt.data.domain.order.event.OrderMessageEvent;
import cn.jiaqiang.chatgpt.data.domain.order.model.entity.PayOrderEntity;
import cn.jiaqiang.chatgpt.data.domain.order.model.entity.ProductEntity;
import cn.jiaqiang.chatgpt.data.domain.order.model.entity.ShopCartEntity;
import cn.jiaqiang.chatgpt.data.domain.order.service.IOrderService;
import cn.jiaqiang.chatgpt.data.infrastructure.event.EventPublisher;
import cn.jiaqiang.chatgpt.data.trigger.http.dto.LTZYPaySuccessDTO;
import cn.jiaqiang.chatgpt.data.trigger.http.dto.SaleProductDTO;
import cn.jiaqiang.chatgpt.data.trigger.mq.RedisStreamMq;
import cn.jiaqiang.chatgpt.data.types.common.Constants;
import cn.jiaqiang.chatgpt.data.types.exception.ChatGPTException;
import cn.jiaqiang.chatgpt.data.types.model.Response;
import cn.jiaqiang.chatgpt.data.types.weixinPay.PaySignUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.eventbus.EventBus;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.partnerpayments.nativepay.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @description 售卖服务
 */
@Slf4j
@RestController()
@CrossOrigin(origins = {"${app.config.cross-origin}", "http://chat.ljq1024.cc"})
@RequestMapping("/api/${app.config.api-version}/sale/")
public class SaleController {

    @Autowired(required = false)
    private NotificationParser notificationParser;

    @Resource
    private IOrderService orderService;

    @Resource
    private IAuthService authService;

    @Resource
    private EventPublisher eventPublisher;

    @Resource
    private OrderMessageEvent orderMessageEvent;

    @Resource
    @Deprecated
    private RedisStreamMq redisStreamMq;

    @Value("${personal.wxpay.key}")
    private String personalKey;

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 商品列表查询
     * 开始地址：http://localhost:8091/api/v1/sale/query_product_list
     * 测试地址：http://apix.natapp1.cc/api/v1/sale/query_product_list
     * <p>
     * curl -X GET \
     * -H "Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJveGZBOXc4LTI..." \
     * -H "Content-Type: application/x-www-form-urlencoded" \
     * http://localhost:8091/api/v1/sale/query_product_list
     */
    @RequestMapping(value = "query_product_list", method = RequestMethod.GET)
    public Response<List<SaleProductDTO>> queryProductList(@RequestHeader("Authorization") String token) {
        try {
            // 1. Token 校验
            boolean success = authService.checkToken(token);
            if (!success) {
                return Response.<List<SaleProductDTO>>builder()
                        .code(Constants.ResponseCode.TOKEN_ERROR.getCode())
                        .info(Constants.ResponseCode.TOKEN_ERROR.getInfo())
                        .build();
            }
            // 2. 查询商品
            List<ProductEntity> productEntityList = orderService.queryProductList();
            log.info("商品查询 {}", JSON.toJSONString(productEntityList));

            List<SaleProductDTO> mallProductDTOS = new ArrayList<>();
            for (ProductEntity productEntity : productEntityList) {
                SaleProductDTO mallProductDTO = SaleProductDTO.builder()
                        .productId(productEntity.getProductId())
                        .productName(productEntity.getProductName())
                        .productDesc(productEntity.getProductDesc())
                        .price(productEntity.getPrice())
                        .quota(productEntity.getQuota())
                        .build();
                mallProductDTOS.add(mallProductDTO);
            }

            // 3. 返回结果
            return Response.<List<SaleProductDTO>>builder()
                    .code(Constants.ResponseCode.SUCCESS.getCode())
                    .info(Constants.ResponseCode.SUCCESS.getInfo())
                    .data(mallProductDTOS)
                    .build();
        } catch (Exception e) {
            log.error("商品查询失败", e);
            return Response.<List<SaleProductDTO>>builder()
                    .code(Constants.ResponseCode.UN_ERROR.getCode())
                    .info(Constants.ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 用户商品下单
     * 开始地址：http://localhost:8091/api/v1/sale/create_pay_order?productId=
     * 测试地址：http://apix.natapp1.cc/api/v1/sale/create_pay_order
     * <p>
     * curl -X POST \
     * -H "Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJveGZBOXc4LTI..." \
     * -H "Content-Type: application/x-www-form-urlencoded" \
     * -d "productId=1001" \
     * http://localhost:8091/api/v1/sale/create_pay_order
     */
    @RequestMapping(value = "create_pay_order", method = RequestMethod.POST)
    public Response<String> createParOrder(@RequestHeader("Authorization") String token, @RequestParam Integer productId) {
        try {
            // 1. Token 校验
            boolean success = authService.checkToken(token);
            if (!success) {
                return Response.<String>builder()
                        .code(Constants.ResponseCode.TOKEN_ERROR.getCode())
                        .info(Constants.ResponseCode.TOKEN_ERROR.getInfo())
                        .build();
            }

            // 2. Token 解析
            String openid = authService.openid(token);
            if (openid == null) {
                throw new ChatGPTException("token 无效!");
            }
            log.info("用户商品下单，根据商品ID创建支付单开始 openid:{}, productId:{}", openid, productId);
            // 生成购物车对象
            ShopCartEntity shopCartEntity = ShopCartEntity.builder()
                    .openid(openid)
                    .productId(productId)
                    .build();
            // 根据购物车对象创建订单对象
            PayOrderEntity payOrder = orderService.createOrder(shopCartEntity);
            if (payOrder == null) {
                return Response.<String>builder()
                        .code(Constants.ResponseCode.UN_ERROR.getCode())
                        .info(Constants.ResponseCode.UN_ERROR.getInfo())
                        .build();
            }
            log.info("用户商品下单，根据商品ID创建支付单完成 openid: {} productId: {} orderPay: {}", openid, productId, payOrder.toString());

            return Response.<String>builder()
                    .code(Constants.ResponseCode.SUCCESS.getCode())
                    .info(Constants.ResponseCode.SUCCESS.getInfo())
                    .data(payOrder.getPayUrl())
                    .build();
        } catch (Exception e) {
            log.error("用户商品下单，根据商品ID创建支付单失败", e);
            return Response.<String>builder()
                    .code(Constants.ResponseCode.UN_ERROR.getCode())
                    .info(Constants.ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 支付回调
     * 开发地址：http:/localhost:8091/api/v1/sale/pay_notify
     * 线上地址：https://你的域名/api/v1/sale/pay_notify
     */
    @PostMapping("wx/pay_notify")
    public void wxPayNotify(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            // 随机串
            String nonceStr = request.getHeader("Wechatpay-Nonce");
            // 微信传递过来的签名
            String signature = request.getHeader("Wechatpay-Signature");
            // 证书序列号（微信平台）
            String serialNo = request.getHeader("Wechatpay-Serial");
            // 时间戳
            String timestamp = request.getHeader("Wechatpay-Timestamp");

            // 构造 RequestParam
            com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                    .serialNumber(serialNo)
                    .nonce(nonceStr)
                    .signature(signature)
                    .timestamp(timestamp)
                    .body(requestBody)
                    .build();

            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
            // 获取支付状态
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            log.info("支付回调结果: {}", tradeState);
            if (Transaction.TradeStateEnum.SUCCESS.equals(tradeState)) {
                // 支付单号
                String orderId = transaction.getOutTradeNo();
                // 交易号
                String transactionId = transaction.getTransactionId();
                // 总金额
                Integer total = transaction.getAmount().getTotal();
                // 支付成功时间
                String successTime = transaction.getSuccessTime();
                log.info("支付成功 orderId:{} total:{} successTime: {}", orderId, total, successTime);
                // 更新订单
                boolean isSuccess = orderService.changeOrderPaySuccess(orderId, transactionId,
                        // 总金额转换为 BigDecimal 类型，然后除以 100，以还原为原始的金额值，
                        // 并使用 RoundingMode.HALF_UP 进行四舍五入保留两位小数
                        new BigDecimal(total).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP),
                        // 时间格式转换
                        dateFormat.parse(successTime));

                if (isSuccess) {
                    // 发布消息
//                    redisStreamMq.post(orderId);
                    // 库存消耗没了以后，发送MQ消息，更新数据库库存
                    eventPublisher.publish(orderMessageEvent.topic(), orderMessageEvent.buildEventMessage(orderId));
                }
                response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
            } else {
                // 支付失败
                response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
            }
        } catch (Exception e) {
            log.error("支付失败", e);
            response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
        }
    }

    /**
     * 蓝图支付回调
     */
    @PostMapping("ltzf/pay_notify")
    public void ltzyPayNotify(String code,String timestamp, String mch_id,
                              String order_no, String out_trade_no, String pay_no,
                              String total_fee, String sign,String pay_channel,
                              String trade_type, String success_time, String attach, String openid,
                              HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            log.info("code = {}", code);
            log.info("timestamp = {}", timestamp);
            log.info("mch_id = {}", mch_id);
            log.info("order_no = {}", order_no);
            log.info("out_trade_no = {}", out_trade_no);
            log.info("pay_no = {}", pay_no);
            log.info("total_fee = {}", total_fee);
            log.info("sign = {}", sign);
            log.info("pay_channel = {}", pay_channel);
            log.info("trade_type = {}", trade_type);
            log.info("success_time = {}", success_time);
            log.info("attach = {}", attach);
            log.info("openid = {}", openid);

            // 获取请求的地址
            String requestUrl = request.getRequestURL().toString();
            log.info("requestUrl = {}", requestUrl);

            // 判断签名
            boolean notifySign = PaySignUtil.checkNotifySign(timestamp, code, mch_id, order_no, out_trade_no,
                    pay_no,total_fee, sign, personalKey);
            if (!notifySign) {
                log.error("支付回调验证失败!");
                response.getWriter().write("FAIL");
                return;
            }

            // 支付成功
            if ("0".equals(code)) {
                log.info("支付成功 orderId:{} total:{} successTime: {}", out_trade_no, total_fee, success_time);
                // 更新订单
                boolean isSuccess = orderService.changeOrderPaySuccess(out_trade_no, pay_no,
                        // 总金额转换为 BigDecimal 类型，然后除以 100，以还原为原始的金额值，
                        // 并使用 RoundingMode.HALF_UP 进行四舍五入保留两位小数
                        BigDecimal.valueOf(Double.parseDouble(total_fee)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP),
                        // 时间格式转换
                        dateFormat.parse(success_time));
                if (isSuccess) {
                    // 发布消息
//                    redisStreamMq.post(out_trade_no);
                    eventPublisher.publish(orderMessageEvent.topic(), orderMessageEvent.buildEventMessage(out_trade_no));
                }
                response.getWriter().write("SUCCESS");
            } else {
                response.getWriter().write("FAIL");
            }

        } catch (Exception e) {
            log.error("支付失败", e);
            response.getWriter().write("FAIL");
        }
    }

}
